
#ifndef _TTG_THREADS_THREAD_MAP_
#define _TTG_THREADS_THREAD_MAP_
#include "Common/Definitions.h"

namespace ttg_internal
{
	namespace threads
	{
		//Creates instance of required type.
		template <class ValueType>
		class DefaultInstanceCreator
		{
			public:
				inline ValueType operator() ()
				{ return ValueType(); }
		};
	}
}

namespace ttg
{
	namespace threads
	{
		//Container, that maps real threads to assigned values.
		//Uses two level synchronization.
		//Note: ValueType should support default constructor.
		template <class ValueType,
				  class InstanceCreator = ttg_internal::threads::DefaultInstanceCreator<ValueType>>
		class ThreadMap
		{
			public:
				std::map<ttg::math::uint64, std::pair<ValueType, size_t>> known_threads;	//ro access without lock
				std::map<ttg::math::uint64, std::pair<ValueType, size_t>> new_threads;		//rw access with lock
				size_t count;
				ttg::threads::FastCriticalSection locker;
			public:
				//Creates empty map.
				inline ThreadMap()
				{ count = 0; }
				//Returns value + index, that was assigned to current thread.
				//If it's the first call for this thread, creates new record.
				std::pair<ValueType *, size_t> getRecord()
				{
					ttg::math::uint64 ID = ttg::threads::CurrentThread::getIdentifier();
					std::map<ttg::math::uint64, std::pair<ValueType, size_t>>::iterator it
							= known_threads.find(ID);
					if (it == known_threads.end())
					{
						std::pair<ValueType, size_t> *res;
						locker.enter();
						it = new_threads.find(ID);
						if (it == new_threads.end())
						{
							new_threads[ID] = std::make_pair(InstanceCreator().operator() (), count++);
							res = &new_threads[ID];
						}
						else
							res = &it->second;
						locker.leave();
						return std::pair<ValueType *, size_t>(&res->first, res->second);
					}
					else
						return std::pair<ValueType *, size_t>(&it->second.first,
															  it->second.second);
				}
				//Returns value, that was assigned to current thread.
				//If it's the first call for this thread, creates new record.
				inline ValueType &getValue()
				{ return *getRecord().first; }
				//Returns index, that was assigned to current thread.
				//If it's the first call for this thread, creates new record.
				inline size_t getIndex()
				{ return getRecord().second; }
				//Returns total count of threads, that are registered.
				size_t getThreadCount()
				{
					size_t res;
					locker.enter();
					res = count;
					locker.leave();
					return res;
				}
				//Rebuilds table, that allows to avoid synchronization for existant threads.
				//Note: It is not thread safe method and should not be called together with other methods.
				void reBuild()
				{
					locker.enter();
					std::map<ttg::math::uint64, std::pair<ValueType, size_t>>::iterator it
							= new_threads.begin();
					while (it != new_threads.end())
					{
						known_threads[it->first] = it->second;
						it++;
					}
					new_threads.clear();
					locker.leave();
				}
				std::vector<ValueType *> createEnumeration()
				{
					std::vector<ValueType *> res;
					//Enumeration for known threads.
					std::map<ttg::math::uint64, std::pair<ValueType, size_t>>::iterator it
							= known_threads.begin();
					while (it != known_threads.end())
						res.push_back(&(it++)->second.first);
					//Enumeration for new threads.
					locker.enter();
					it = new_threads.begin();
					while (it != new_threads.end())
						res.push_back(&(it++)->second.first);
					locker.leave();
					//Returning result.
					return res;
				}
		};
	}
}

#endif
